#ifndef __HMETIS_IF_CONFIG_H__
#define __HMETIS_IF_CONFIG_H__

#include <string>
#include <sstream>
#include <cassert>

class hmetis_if_config {
  public:
    enum PartitionType {
      PartitionTypeRecursive = 0,
      PartitionTypeKWay
    };
    enum CoarseningType {
      CoarseningTypeFC = 0,
      CoarseningTypeGreedyFC,
      CoarseningTypeFC2,
      CoarseningTypeGreedyFC2,
      CoarseningTypeFCGFC,
      CoarseningTypeFC2GFC2,
      CoarseningTypeFCGFCFC2GFC2,
      CoarseningTypeEdge,
      CoarseningTypeGreedyEdge,
      CoarseningTypeEdge2,
      CoarseningTypeGreedyEdge2
    };
    enum RefinementType {
      RefinementTypeFastFM = 0,
      RefinementTypeMediumFM,
      RefinementTypeSlowFM,
      RefinementTypeRandomKWay,
      RefinementTypeFastKWay,
      RefinementTypeMediumKWay,
      RefinementTypeSlowKWay
    };
    enum ObjectiveFunction {
      ObjectiveFunctionMinCut = 0,
      ObjectiveFunctionMinSOED
    };

      static const PartitionType _partition_type = PartitionTypeKWay;
      static const CoarseningType _coarsening_type = CoarseningTypeGreedyEdge;
      static const RefinementType _refinement_type = RefinementTypeFastKWay;
      static const ObjectiveFunction _objective_function = ObjectiveFunctionMinSOED;
      static const float _unbalance_factor = 5;
      static const int _num_runs = 1;
      static const int _num_vcycle_solutions = 1;
      static const int _max_net_size_for_coarsening = 50;
      static const int _max_net_size_for_refinement = 50;
      static const bool _reconstruct_partial_nets = false;
      static const bool _final_kway_refine = true;
      static const int _rng_seed = 0;
      static const bool _show_coarsening_progress = false;
      static const bool _show_initial_cuts = false;
      static const bool _show_refinement_progress = false;
      static const bool _show_bisection_stats = false;
      static const bool _show_bisection_stats_2 = false;
      static const bool _show_timing_stats = false;
      static const bool _show_detailed_bisection_stats = false;
      static const bool _show_cell_move_stats = false;

       PartitionType partition_type;
       CoarseningType coarsening_type;
       RefinementType refinement_type;
       ObjectiveFunction objective_function;
       float unbalance_factor;
       int num_runs;
       int num_vcycle_solutions;
       int max_net_size_for_coarsening;
       int max_net_size_for_refinement;
       bool reconstruct_partial_nets;
       bool final_kway_refine;
       int rng_seed;
       bool show_coarsening_progress;
       bool show_initial_cuts;
       bool show_refinement_progress;
       bool show_bisection_stats;
       bool show_bisection_stats_2;
       bool show_timing_stats;
       bool show_detailed_bisection_stats;
       bool show_cell_move_stats;

    hmetis_if_config() {
      partition_type = _partition_type;
      coarsening_type = _coarsening_type;
      refinement_type = _refinement_type;
      objective_function = _objective_function;
      unbalance_factor = _unbalance_factor;
      num_runs = _num_runs;
      num_vcycle_solutions = _num_vcycle_solutions;
      max_net_size_for_coarsening = _max_net_size_for_coarsening;
      max_net_size_for_refinement = _max_net_size_for_refinement;
      reconstruct_partial_nets = _reconstruct_partial_nets;
      final_kway_refine = _final_kway_refine;
      rng_seed = _rng_seed;
      show_coarsening_progress = _show_coarsening_progress;
      show_initial_cuts = _show_initial_cuts;
      show_refinement_progress = _show_refinement_progress;
      show_bisection_stats = _show_bisection_stats;
      show_bisection_stats_2 = _show_bisection_stats_2;
      show_timing_stats = _show_timing_stats;
      show_detailed_bisection_stats = _show_detailed_bisection_stats;
      show_cell_move_stats = _show_cell_move_stats;
    }
      
       
     std::string get_config_string() const
    {
      std::stringstream s;
      {
        s << "-ptype=";
        switch(partition_type) {
          case PartitionTypeRecursive: s << "rb"; break;
          case PartitionTypeKWay: s << "kway"; break;
          default: assert(0); break;
        }
      }
      s << " ";
      {
        s << "-ctype=";
        switch(coarsening_type) {
          case CoarseningTypeFC: s << "fc1"; break;
          case CoarseningTypeGreedyFC: s << "gfc1"; break;
          case CoarseningTypeFC2: s << "fc2"; break;
          case CoarseningTypeGreedyFC2: s << "gfc2"; break;
          case CoarseningTypeFCGFC: s << "h1"; break;
          case CoarseningTypeFC2GFC2: s << "h2"; break;
          case CoarseningTypeFCGFCFC2GFC2: s << "h12"; break;
          case CoarseningTypeEdge: s << "edge1"; break;
          case CoarseningTypeGreedyEdge: s << "gedge1"; break;
          case CoarseningTypeEdge2: s << "edge2"; break;
          case CoarseningTypeGreedyEdge2: s << "gedge2"; break;
          default: assert(0); break;
        }
      }
      s << " ";
      {
        s << "-rtype=";
        switch(refinement_type) {
          case RefinementTypeFastFM: s << "fast"; break;
          case RefinementTypeMediumFM: s << "moderate"; break;
          case RefinementTypeSlowFM: s << "slow"; break;
          case RefinementTypeRandomKWay: s << "krandom"; break;
          case RefinementTypeFastKWay: s << "kpfast"; break;
          case RefinementTypeMediumKWay: s << "kpmoderate"; break;
          case RefinementTypeSlowKWay: s << "kpslow"; break;
          default: assert(0); break;
        }
      }
      s << " ";
      {
        s << "-otype=";
        switch(objective_function) {
          case ObjectiveFunctionMinCut: s << "cut"; break;
          case ObjectiveFunctionMinSOED: s << "soed"; break;
          default: assert(0); break;
        }
      }
      s << " ";
      {
        s << "-ufactor=" << unbalance_factor << " ";
      }
      {
        s << "-nruns=" << num_runs << " ";
      }
      {
        s << "-nvcycles=" << num_vcycle_solutions << " ";
      }
      {
        s << "-cmaxnet=" << max_net_size_for_coarsening << " ";
      }
      {
        s << "-rmaxnet=" << max_net_size_for_refinement << " ";
      }
      if(reconstruct_partial_nets) s << "-re ";
      if(final_kway_refine) s << "-kwayrefine ";
      s << "-seed=" << rng_seed << " ";
      {
        int debug = 0;
        if(show_coarsening_progress) debug += (1 << 0);
        if(show_initial_cuts) debug += (1 << 1);
        if(show_refinement_progress) debug += (1 << 2);
        if(show_bisection_stats) debug += (1 << 3);
        if(show_bisection_stats_2) debug += (1 << 4);
        if(show_timing_stats) debug += (1 << 5);
        if(show_detailed_bisection_stats) debug += (1 << 7);
        if(show_cell_move_stats) debug += (1 << 8);
        s << "-dbglvl=" << debug;
      }
      return s.str();
    }
};

#endif //#ifndef __HMETIS_IF_CONFIG_H__
